<?php
/**
 * Created by PhpStorm.
 * User: Administrator
 * Date: 2024/4/23
 * Time: 15:19
 */

namespace app\logic\index\pay;


use app\common\lib\ApplePay;
use app\common\lib\Common;
use app\common\lib\Constant;
use app\common\lib\RedisQueue;
use app\exception\IndexException;
use app\logic\BaseLogic;
use app\model\pay\ApplePayNotifyLogModel;
use app\model\pay\AppleSubscribeLogModel;
use app\model\product\InternalProductModel;
use app\model\product\VipProductModel;
use app\model\user\UserIncomeFlowModel;
use app\model\user\UserInviteRelationModel;
use app\model\user\UserModel;
use app\model\user\UserPointFlowModel;
use app\model\user\UserRechargeOrderIncomeModel;
use app\model\user\UserRechargeOrderModel;
use support\Db;
use support\Log;

class PayLogic extends BaseLogic
{
    protected $model;

    protected static $instance;

    public function __construct()
    {
        parent::__construct();
        $this->model = \app\model\product\InternalProductModel::getInstance();
    }

    public static function getInstance()
    {
//        if(is_object(self::$instance)){
//            return self::$instance;
//        }

        return  new self();
    }

    public function getReproductList($param)
    {
        $where = [
            'isdel'=>0,
            'status'=>1,
            'platform'=>$param['platform']??'ios',
        ];
        if(!empty($param['name'])){
            $where['name'] = $param['name'];
        }
        $fields = ['id','name','sale_price','origin_price','product_id','remark','tip_text','point_nums','platform',Db::Raw('0 is_sub')];
        $order = ['sort', 'desc'];

        $list =  $this->model->index($where, $fields, $order);

        return $list;
    }

    public function getVipproductList($param)
    {
        $where = [
            'isdel'=>0,
            'status'=>1,
            'platform'=>$param['platform']??'ios',
        ];
        if(!empty($param['name'])){
            $where['name'] = $param['name'];
        }else{
            $where[] = ['name','not like','%优惠%'];
        }
        $fields = ['id','name','sale_price','origin_price','product_id','remark','tip_text','point_nums','platform','unit',Db::Raw('1 is_sub')];
        $order = ['sort', 'desc'];

        $list =  VipProductModel::getInstance()->index($where, $fields, $order);

        return $list;
    }

    public function applePay($param)
    {
        Log::info('1. applePay开始：传入参数param', $param);

        $res = Common::setnx('applePay_'.request()->curUserId);

        if($res==false){
            throw new IndexException(4020,'不可频繁请求');
        }

        //todo 校验
        $validateResult = ApplePay::getInstance()->validate($param['receipt_data'], $param['trade_no']);

        if (empty($validateResult['receipt']) && empty($validateResult['receipt']['in_app'])) {
            $find = UserRechargeOrderModel::getInstance()->getWhere([['trade_no', '=', $param['trade_no']]])->first();
            if ($find && $find->order_status != Constant::ORDER_STATUS_PAY_SUCCESS) {
                $find->order_status = Constant::ORDER_STATUS_VALIDATE_FAIL;
                $find->fail_reason  = '苹果校验失败';
                $find->save();
            }

            throw new IndexException(4020, '苹果校验失败');
        }

        Log::info('2. applePay校验：validateResult', $validateResult);

        //todo 业务逻辑处理
        $order = $this->dealApplePayOrder($validateResult, $param);

        return $order;
    }

    public function dealApplePayOrder($validateResult, $param)
    {
        $resultData = $validateResult['receipt']['in_app'];

        //保存购买记录
        foreach($resultData as $val){
            $autoParams = [
                'table'=>'video_apple_pay_log',
                'attributes'=>$val,
            ];
            $this->autoCreateTableAndInsertData($autoParams);
        }
        //AppleSubscribeLogModel::getInstance()->insertData($resultData);

        $tradeMaps       = [];
        $tradeNos        = [];
        $originaTradeNos = [];
        foreach ($resultData as $result) {
            //过滤沙盒订单
            if(in_array($result['original_transaction_id'],['2000000661557401','2000000681513734','2000000609883539'])){
                continue;
            }
            $tradeMaps[$result['transaction_id']] = $result;
            $tradeNos[]                           = $result['transaction_id'];
            $originaTradeNos[]                    = $result['original_transaction_id'];
        }

        $originaTradeNos && $originaTradeNos = array_unique($originaTradeNos);
        $orders = UserRechargeOrderModel::getInstance()->getWhere([['original_trade_no', 'in', $originaTradeNos]])->get();

        Log::info('3. applePay 查看订单数据：orders ' . json_encode($orders), []);

        //todo 1 已经存在的订单处理
        $orderTadeNos = [];
        foreach ($orders as $val) {
            if (!isset($tradeMaps[$val['trade_no']])) {
                continue;
            }

            //如果是恢复购买，不是相同用户订单，跳过
            if ($param['is_reply'] == 1 && request()->curUserId != $val->user_id) {
                continue;
            }

            //取消和退款状态的跳过
            if (in_array($val['order_status'], [Constant::ORDER_STATUS_CANCEL, Constant::ORDER_STATUS_REFUND])) {
                continue;
            }

            $orderTadeNos[] = $val['trade_no'];
            $trade          = $tradeMaps[$val['trade_no']];

            if (strtoupper($trade['in_app_ownership_type']) == 'PURCHASED') {
                if ($val['trade_no'] == $param['trade_no'] && request()->curUserId != $val->user_id) {
                    $val->user_id = request()->curUserId;
                }
                $val->order_status  = Constant::ORDER_STATUS_PAY_SUCCESS;
                $val->pay_status    = Constant::ORDER_PAY_STATUS_SUCCESS;
                $val->ip            = request()->getRealIp();
                $val->device_number = request()->deviceNumber ?? '';
                $val->isrenew       = $trade['original_transaction_id'] == $val->trade_no ? 0 : 1;
                $val->save();
            }
        }

        //todo 2 不存在的订单处理  检查还有交易是否还没创建的订单，需要创建
        $orderTadeNos && $orderTadeNos = array_unique($orderTadeNos);
        $insertTradeNos = array_diff($tradeNos, $orderTadeNos);
        foreach ($insertTradeNos as $transactionId) {
            $trade = $tradeMaps[$transactionId];

            // 检查是否收到苹果回调的退款通知，如果有则继续查一下个订单
            $refund_orders = UserRechargeOrderModel::getInstance()->getWhere(['original_trade_no'=>$trade['original_transaction_id'], 'order_status'=>Constant::ORDER_STATUS_REFUND])->get();
            Log::info('检查是否收到苹果回调的退款通知：refund_orders ' . json_encode($refund_orders), []);
            if (count($refund_orders) > 0) {
                continue;
            }

            $vipProduct = VipProductModel::getInstance()->getWhere(['product_id'=>$trade['product_id'],'isdel'=>0])->first();
            $reProduct = InternalProductModel::getInstance()->getWhere(['product_id'=>$trade['product_id'],'isdel'=>0])->first();
            $maxId =  UserRechargeOrderModel::getInstance()->getWhere([['order_no','>',0]])->max('order_no');
            $orderOn = Common::getSnCode($maxId,'60',6, 2);
            $orderData = [
                'user_sn'           => request()->curUserId ?? 0,
                'order_no'          => $orderOn,
                'product_type'      => !empty($vipProduct) ? 1 : 2,
                'trade_no'          => $transactionId,
                'original_trade_no' => $trade['original_transaction_id'],
                'money'             => $vipProduct['sale_price'] ?? ($reProduct['sale_price'] ?? 0),
                'payment'           => 1,

                'isrenew'                  => $trade['original_transaction_id'] != $transactionId ? 1 : 0,
                'product_id'               => $trade['product_id'],
                'expires_date'             => !empty($trade['expires_date_ms']) ? ($trade['expires_date_ms'] / 1000) : 0,
                'update_pay_status_source' => 1,
                'point_nums'               => !empty($vipProduct) ? $vipProduct['point_nums'] : (!empty($reProduct) ? $reProduct['point_nums'] : 0),
                'ip'                       => request()->getRealIp(),
                'device_number'            => request()->deviceNumber ?? '',
            ];
            if (strtoupper($trade['in_app_ownership_type']) == 'PURCHASED') {
                $orderData['order_status'] = Constant::ORDER_STATUS_PAY_SUCCESS;
                $orderData['pay_status'] = Constant::ORDER_PAY_STATUS_SUCCESS;
                $orderData['pay_time'] = date('Y-m-d H:i:s', $trade['purchase_date_ms'] / 1000);
            }
            UserRechargeOrderModel::getInstance()->insertGetId($orderData);
        }

        //todo 3 防止同一个原始单号，没有用户id的单号,做一次全部检查并更新
        foreach ($originaTradeNos as $originalTransactionId) {
            $this->getOrderAndUpdateUserId($originalTransactionId);
        }

        //todo 4 查看当前订单,做下一步业务处理
        $where = [
            'order_status' => Constant::ORDER_STATUS_PAY_SUCCESS,
            'pay_status'   => Constant::ORDER_PAY_STATUS_SUCCESS,
            'payment'      => 1,
        ];
        $where1 = $where;
        $where1[] = ['original_trade_no', 'in', $originaTradeNos];
        $where1[] = ['user_sn', '<>', 0];
        $order = UserRechargeOrderModel::getInstance()->getWhere($where1)->orderBy('pay_time', 'desc')->first();

        $user = [];
        if($order){
            $user = $this->dealApplePayOrderAfter($order);

            //加入巨量引擎支付回传队列
            //生成唯一的请求id
            $requestId = Common::getRequestId();
            // 队列名
            $queue = 'oceanengineAttribution';
            // 数据，可以直接传数组，无需序列化
            $data = ['requestid' => $requestId, 'user_sn'=>$order['user_sn'],'type'=>'pay' ,'amount'=>$order['money']];
            // 投递消息
            RedisQueue::getInstance()->sendQueue($queue, $data);
        }

        return $user;

    }

    public function applePayNotify($postDataContent)
    {
        try {
            $result = ApplePay::getInstance()->notify($postDataContent);
            $count  = ApplePayNotifyLogModel::getInstance()->getWhere(['notification_uuid' => $result['notificationUUID'], 'result' => 0])->count();
            if ($count > 0 && !empty($result['transactionInfo']) && is_array($result['transactionInfo'])) {
                switch ($result['is_renew']) {
                    case -1:
                        //todo 续订相关状态
                        $this->notifyDealPay($result, -1);
                        break;
                    case 0:
                        //todo 用户取消订阅或者订阅过期
                        $this->notifyDealPay($result, 0);
                        break;
                    case 1:
                        //todo 续期成功，订阅成功通知
                        $this->notifyDealPay($result, 1);
                        break;
                    case 2:
                        //todo 退款，取消订单
                        $this->notifyDealPay($result, 2);
                        break;
                }

                ApplepayNotifyLogModel::getInstance()->getWhere(['notification_uuid' => $result['notificationUUID']])->update(['result' => 1]);
            }

            return true;
        } catch (IndexException $e) {
            throw $e;
        }

    }

    protected function notifyDealPay($notifyData, $isRenew)
    {
        $transactionInfo       = $notifyData['transactionInfo'];
        $originalTransactionId = $transactionInfo['originalTransactionId'];
        $transactionId         = $transactionInfo['transactionId'];
        $productId             = $transactionInfo['productId'];

        $order = UserRechargeOrderModel::getInstance()->getWhere(['trade_no' => $transactionId])->first();
        if ($isRenew == -1) {
            if ($order) {
                $order->notification_type = $notifyData['notificationType'] ?? '';
                $order->subtype           = $notifyData['subtype'] ?? '';
                $order->notify_time       = time();
                $order->save();
            }
            return $order;
        }

        $payStatus = Constant::ORDER_PAY_STATUS_SUCCESS;
        if ($isRenew == 2) {
            $OrderStatus = Constant::ORDER_STATUS_REFUND;
        } elseif ($isRenew == 0) {
            $OrderStatus = Constant::ORDER_STATUS_CANCEL;
            $payStatus   = Constant::ORDER_PAY_STATUS_WAIT;
        } else {
            $OrderStatus = Constant::ORDER_STATUS_PAY_SUCCESS;
        }

        $orderSn = '';
        //todo 2 添加或更新订单信息
        if ($order == false) {
            //todo 添加订单 查不出来，可能没有创建订单，或者还没有交易号，需要创建当前交易订单
            $vipProduct = VipProductModel::getInstance()->getWhere(['product_id'=>$productId,'isdel'=>0])->first();
            $reProduct = InternalProductModel::getInstance()->getWhere(['product_id'=>$productId,'isdel'=>0])->first();
            $maxId =  UserRechargeOrderModel::getInstance()->getWhere([['order_no','>',0]])->max('order_no');
            $orderOn = Common::getSnCode($maxId,'60', 6, 2);
            $orderData = [
                'user_sn'                  => 0,
                'order_no'                 => $orderOn,
                'product_type'             => !empty($vipProduct) ? 1 : 2,
                'trade_no'                 => $transactionId,
                'original_trade_no'        => $originalTransactionId,
                'order_status'             => $OrderStatus,
                'pay_status'               => $payStatus,
                'pay_time'                 => date('Y-m-d H:i:s', $transactionInfo['purchaseDate'] / 1000),
                'money'                    => $vipProduct['sale_price']??($reProduct['sale_price']??0),
                'payment'                  => 1,

                'isrenew'                  => $originalTransactionId != $transactionId ? 1 : 0,
                'product_id'               => $productId,
                'expires_date'             => !empty($transactionInfo['expiresDate']) ? ($transactionInfo['expiresDate'] / 1000) : 0,
                'update_pay_status_source' => 2,
                'notification_type'        => $notifyData['notificationType'] ?? '',
                'subtype'                  => $notifyData['subtype'] ?? '',
                'notify_time'              => time(),
                'point_nums'              => !empty($vipProduct) ? $vipProduct['point_nums'] : (!empty($reProduct)?$reProduct['point_nums']:0),
            ];

            UserRechargeOrderModel::getInstance()->insertGetId($orderData);
            $orderSn  = $orderOn;
        } else {
            //todo 更新订单信息
            if (strtoupper($transactionInfo['inAppOwnershipType']) == 'PURCHASED') {
                $order->order_status = $OrderStatus;
                $order->pay_status   = $payStatus;
                $order->isrenew      = $originalTransactionId != $transactionId ? 1 : 0;

                $order->notification_type = $notifyData['notificationType'] ?? '';
                $order->subtype           = $notifyData['subtype'] ?? '';
                $order->notify_time       = time();

                $order->save();
                $orderSn  = $order->order_no;
            }
        }

        //todo 3 防止同一个原始单号，没有用户id的单号,做一次全部检查并更新
        $this->getOrderAndUpdateUserId($originalTransactionId);

        //todo 4 查看当前订单,做下一步业务处理
        $where = [
            'order_status' => Constant::ORDER_STATUS_PAY_SUCCESS,
            'pay_status'   => Constant::ORDER_PAY_STATUS_SUCCESS,
            'trade_no'     => $transactionId,
            'payment'     => 1,
        ];
        $order = UserRechargeOrderModel::getInstance()->getWhere($where)->orderBy('pay_time', 'desc')->first();

        $user = [];
        if($order){
            $user = $this->dealApplePayOrderAfter($order);
        }

        //如果是退款就要加入退款队列
        if($OrderStatus==Constant::ORDER_STATUS_REFUND){
            //生成唯一的请求id
            $requestId = Common::getRequestId();

            // 队列名
            $queue = 'refundDealWith';
            // 数据，可以直接传数组，无需序列化
            $data = ['requestid' => $requestId, 'order_no' => $orderSn];
            // 投递消息
            RedisQueue::getInstance()->sendQueue($queue, $data);
        }
        return $transactionId;
    }

    /**
     * 防止同一个原始单号，没有用户id的单号,做一次全部检查并更新
     * @param $originaTradeNo
     * @return bool
     */
    protected function getOrderAndUpdateUserId($originaTradeNo)
    {
        $userId = request()->curUserId;

        $userId == false && $userId = UserRechargeOrderModel::getInstance()->getWhere([['original_trade_no', '=', $originaTradeNo], ['user_sn', '<>', '0']])
            ->orderBy('pay_time', 'desc')->value('user_sn');

        $userId && UserRechargeOrderModel::getInstance()->getWhere([['original_trade_no', '=', $originaTradeNo], ['user_sn', '=', '0']])
            ->update(['user_sn' => $userId]);

        return true;
    }

    /**
     * 交易成功后的业务逻辑处理
     * @param $order
     * @return bool
     */
    protected function dealApplePayOrderAfter($order)
    {
        $userSn = $order['user_sn']??'';
        if($userSn==false){
            return false;
        }
        $user = UserModel::getInstance()->getWhere(['user_sn'=>$userSn])->first();
        if($user==false){
            return false;
        }

        //todo 1 获取当前用户的订阅订单
        $where = [
            ['payment', '=', 1],
            ['product_type', '=', 1],
            ['user_sn', '=', $userSn],
            ['order_status', '=', Constant::ORDER_STATUS_PAY_SUCCESS],
            ['pay_status', '=', Constant::ORDER_PAY_STATUS_SUCCESS],
            ['pay_time', '<>', ''],
            ['expires_date', '>=', strtotime(date('Y-m-d'))],
        ];
        $order = UserRechargeOrderModel::getInstance()->getWhere($where)->orderBy('point_nums','desc')->first();
        $expiresDate  = UserRechargeOrderModel::getInstance()->getWhere($where)->max('expires_date');
        if($expiresDate){
            $this->dealApplePayOrderAfterSaveData($user,$order,$expiresDate);
        }

        //todo 2 获取当前用户的内购订单
        $where = [
            ['payment', '=', 1],
            ['product_type', '=', 2],
            ['user_sn', '=', $userSn],
            ['order_status', '=', Constant::ORDER_STATUS_PAY_SUCCESS],
            ['pay_status', '=', Constant::ORDER_PAY_STATUS_SUCCESS],
            ['pay_time', '>', date('Y-m-d H:i:s',(time()-3600))], //支付时间在一个小时之内的
        ];
        $orders  = UserRechargeOrderModel::getInstance()->getWhere($where)->get();
        Log::info('4. applePay 获取当前用户的内购订单：orders ' . json_encode($orders), []);
        foreach($orders as $order){
            $where = [
                'user_sn'=>$userSn,
                'type'=>2,
                'way'=>1,
                'sourceid'=>$order['id'],
                'source_table'=>UserRechargeOrderModel::getInstance()->getTable()
            ];
           $count = UserPointFlowModel::getInstance()->getWhere($where)->count();
           if($count==false){
               $this->dealApplePayOrderAfterSaveData($user,$order);
           }
        }

        return $user;
    }

    protected function dealApplePayOrderAfterSaveData($user,$order,$expiresDate='')
    {
        $userSn = $user['user_sn'];
        try{
            Db::connection('mysql')->beginTransaction();
            //todo 2 更新vip用户有效期
            if($expiresDate){
                $user->vip_expire_time = date('Y-m-d H:i:s',$expiresDate);
                $user->is_vip = 1;
                $user->save();
            }

            //todo 3 今天没送点数，现在立即就送点数
            if($order['product_type']==1){
                $where = [
                    'user_sn'=>$userSn,
                    'type'=>1,
                    'way'=>1,
                    ['created_at','>=',date('Y-m-d 00:00:00')]
                ];
                $pointNums = (int) UserPointFlowModel::getInstance()->getWhere($where)->sum('nums');
                if($pointNums<$order['point_nums']){
                    $insert = [
                        'user_sn'=>$userSn,
                        'nums'=>round($order['point_nums']-$pointNums),
                        'type'=>1,
                        'way'=>1,
                        'sourceid'=>$order['id'],
                        'source_table'=>UserRechargeOrderModel::getInstance()->getTable(),
                    ];
                    UserPointFlowModel::getInstance()->insertGetId($insert);
                }
            }elseif($order['product_type']==2){
                $insert = [
                    'user_sn'=>$userSn,
                    'nums'=>round($order['point_nums']),
                    'type'=>2,
                    'way'=>1,
                    'sourceid'=>$order['id'],
                    'source_table'=>UserRechargeOrderModel::getInstance()->getTable(),
                ];
                UserPointFlowModel::getInstance()->insertGetId($insert);
            }

            //todo 4 给邀请用户分成
            $parentUserSn = UserInviteRelationModel::getInstance()->getWhere(['invite_user_sn'=>$userSn,'level'=>1])->value('user_sn');
            $parentUser = UserModel::getInstance()->getWhere(['user_sn'=>$parentUserSn])->first();
            //是否已经分过
            $where = [
                'user_sn'=>$parentUserSn,
                'income_source_user_sn'=>$userSn,
                'order_no'=>$order['order_no'],
            ];
            $count = UserRechargeOrderIncomeModel::getInstance()->getWhere($where)->count();

            if($parentUser && $count==false){

                $levelData = config('param.vip_level'.$parentUser['agent_level']);
                $incomeRate = ($levelData['income_rate']??10);

                $insert = [
                    'user_sn'=>$parentUserSn,
                    'order_no'=>$order['order_no'],
                    'level_type'=>1,
                    'income_source_user_sn'=>$userSn,
                    'income_amount'=>round($order['money']*$incomeRate/100,2),
                    'pay_amount'=>$order['money'],
                    'pay_time'=>$order['pay_time'],
                    'agent_level'=>$parentUser['agent_level'],
                    'reward_rate'=>$incomeRate,
                    'product_type'=>$order['product_type'],
                ];
                $incomeId = UserRechargeOrderIncomeModel::getInstance()->insertGetId($insert);
                $insertFlow = [
                    'user_sn'=>$parentUserSn,
                    'amount'=>$insert['income_amount'],
                    'type'=>1,
                    'source_table'=>UserRechargeOrderIncomeModel::getInstance()->getTable(),
                    'sourceid'=>$incomeId,
                    'income_source_user_sn'=>$userSn,
                    'income_date'=>$order['pay_time'],
                ];
                UserIncomeFlowModel::getInstance()->insertGetId($insertFlow);
            }
            Db::connection('mysql')->commit();
        }catch (\Exception $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }catch (\Throwable $e){
            Db::connection('mysql')->rollBack();
            throw $e;
        }

        return true;
    }
}